﻿#region Copyright & licence

// This file is part of Refix.
// 
// Refix is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
// 
// Refix is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
// 
// You should have received a copy of the GNU Lesser General Public
// License along with Refix.  If not, see <http://www.gnu.org/licenses/>.
// 
// Copyright (C) 2010-11 David Musgrove and others.

#endregion

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;

using Refix.Core.Properties;
using Refix.Core.Repository;

namespace Refix.Core.Commands
{
    public class SourceControl : Command
    {
        private readonly string[] _patterns = new[]
                                             {
                                                 @".refix",
                                                 @"*.rfx*"
                                             };

        private const string MERCURIAL_CONTENT = @"

# Added by Refix
syntax: glob
";

        private const string GIT_CONTENT = @"

# Added by Refix
s";

        public string SccProvider { get; set; }

        protected override string HelpText
        {
            get { return ResourceDispenser.GetString("SOURCE_CONTROL_HELP"); }
        }

        public override bool Validate()
        {
            if (!base.Validate())
            {
                return false;
            }
            if (Options.Arguments.Count != 1)
            {
                OutputWriter.WriteLine(OutputVerbosity.Quiet, ResourceDispenser.GetString("WRONG_NUMBER_OF_ARGUMENTS"));
                ShowHelp();
                return false;
            }
            string sccProvider = Options.Arguments[0].ToUpperInvariant();
            switch (sccProvider)
            {
                case "HG":
                case "SVN":
                case "GIT":
                    break;
                default:
                    OutputWriter.WriteLine(OutputVerbosity.Quiet, ResourceDispenser.GetString("SOURCE_CONTROL_UNKNOWN_PROVIDER"));
                    ShowHelp();
                    return false;
            }
            SccProvider = sccProvider;
            return true;
        }

        public override bool Execute()
        {
            string targetFolder = Directory.GetCurrentDirectory();
            switch (SccProvider)
            {
                case "SVN":
                    return AddToSvnIgnoreProperty(targetFolder);
                case "HG":
                    return AddToHgIgnoreFile(targetFolder);
                case "GIT":
                    return AddToGitIgnoreFile(targetFolder);
                default:
                    return false;
            }
        }

        private bool AddToGitIgnoreFile(string targetFolder)
        {
            string fileName = Path.Combine(targetFolder, ".gitignore");
            AddMissingPatternsToFile(fileName, GIT_CONTENT);
            OutputWriter.WriteLine(ResourceDispenser.GetString("SOURCE_CONTROL_ADDED_TO_GIT"));
            return true;
        }

        private bool AddToHgIgnoreFile(string targetFolder)
        {
            string fileName = Path.Combine(targetFolder, ".hgignore");
            AddMissingPatternsToFile(fileName, MERCURIAL_CONTENT);
            OutputWriter.WriteLine(ResourceDispenser.GetString("SOURCE_CONTROL_ADDED_TO_MERCURIAL"));
            return true;
        }

        private bool AddMissingPatternsToFile(string fileName, string toAdd)
        {
            bool anyAdded = false;
            string[] existingContent = File.Exists(fileName)
                                           ? File.ReadAllLines(fileName)
                                           : new string[] {};
            foreach (var pattern in _patterns)
            {
                if (!existingContent.Any(s => s == pattern))
                {
                    toAdd += pattern + Environment.NewLine;
                    anyAdded = true;
                }
            }   
            if (anyAdded)
            {
                if (!File.Exists(fileName))
                {
                    File.WriteAllText(fileName, "");
                }
                File.AppendAllText(fileName, toAdd);
                return true;
            }
            return false;
        }

        private bool AddToSvnIgnoreProperty(string targetFolder)
        {
            string tempFileName = Path.GetTempFileName();
            var startInfo = new ProcessStartInfo
                            {
                                FileName = "svn.exe",
                                Arguments = "propget svn:ignore .",
                                UseShellExecute = false,
                                CreateNoWindow = true,
                                RedirectStandardOutput = true
                            };
            Process process = Process.Start(startInfo);
            string output = process.StandardOutput.ReadToEnd();
            process.WaitForExit(30000);
            if (process.ExitCode != 0)
            {
                OutputWriter.WriteLine(ResourceDispenser.GetString("SOURCE_CONTROL_SUBVERSION_COMMAND_FAILED"));
                return false;
            }
            File.WriteAllText(tempFileName, output);
            if (AddMissingPatternsToFile(tempFileName, ""))
            {
                startInfo = new ProcessStartInfo
                            {
                                FileName = "svn.exe",
                                Arguments = "propset svn:ignore . -F \"" + tempFileName + "\"",
                                UseShellExecute = false,
                                CreateNoWindow = true,
                                RedirectStandardOutput = true
                            };
                process = Process.Start(startInfo);
                output = process.StandardOutput.ReadToEnd();
                process.WaitForExit(30000);
                if (process.ExitCode != 0)
                {
                    OutputWriter.WriteLine(ResourceDispenser.GetString("SOURCE_CONTROL_SUBVERSION_COMMAND_FAILED"));
                    return false;
                }
            }
            File.Delete(tempFileName);
            OutputWriter.WriteLine(ResourceDispenser.GetString("SOURCE_CONTROL_ADDED_TO_SUBVERSION"));
            return true;
        }
    }
}